package com.hua.designpattern.behavioral.interpreter;

import java.util.LinkedList;

public class HandleMathOperation {
	private String targetExpression;

	public HandleMathOperation(String targetExpression) {
		super();
		this.targetExpression = targetExpression.replaceAll(" ", "");
	}

	public double doHandle() {
		LinkedList<InterpreterInterface> dataStack = new LinkedList<InterpreterInterface>();
		LinkedList<Character> operatorStack = new LinkedList<Character>();
		StringBuffer dataBuffer = new StringBuffer();
		char[] targetArray = targetExpression.toCharArray();

		int index = 0;
		while (index < targetArray.length) {
			char targetChar = targetArray[index];
			if (targetChar >= '0' && targetChar <= '9') {
				dataBuffer.append(targetChar);
				index++;
			} else {
				if (dataBuffer.length() != 0) {
					dataStack.push(new TerminalExpression(Double.parseDouble(dataBuffer.toString())));
					dataBuffer = new StringBuffer();
				}

				int opStack = getOperatorPriority(operatorStack.peekFirst());
				int opCurrent = getOperatorPriority(targetChar);
				if (opStack < opCurrent || opStack == 0) {
					operatorStack.push(targetChar);
					index++;
				} else {
					InterpreterInterface right = dataStack.pollFirst();
					InterpreterInterface left = dataStack.pollFirst();
					Character operator = operatorStack.pollFirst();
					dataStack.push(doHandleMath(left, right, operator));
				}
			}
			if (index == targetArray.length) {
				dataStack.push(new TerminalExpression(Double.parseDouble(dataBuffer.toString())));
				dataBuffer = null;
			}
		}
		while (dataStack.size() != 1) {
			InterpreterInterface right = dataStack.pollLast();
			InterpreterInterface left = dataStack.pollLast();
			Character operator = operatorStack.pollLast();
			dataStack.push(doHandleMath(left, right, operator));
		}

		return dataStack.pollLast().interpreter(targetExpression);
	}

	private InterpreterInterface doHandleMath(InterpreterInterface left, InterpreterInterface right,
			Character operator) {
		InterpreterInterface res = null;
		if (left == null || right == null) {
			throw new UnsupportedOperationException(
					"can not do operator case by null: " + left == null ? "left" : "right");
		}
		switch (operator) {
		case '+':
			res = new NonterminalExpressionPlus(left, right);
			break;
		case '-':
			res = new NonterminalExpressionSubtract(left, right);
			break;
		case '*':
			res = new NonterminalExpressionMultiply(left, right);
			break;
		case '/':
			res = new NonterminalExpressionDivision(left, right);
			break;
		default:
			break;
		}
		return res;
	}

	private int getOperatorPriority(Character operator) {
		if (operator == null) {
			return 0;
		} else if (operator.equals('+') || operator.equals('-')) {
			return 1;
		} else if (operator.equals('*') || operator.equals('/')) {
			return 3;
		} else {
			throw new UnsupportedOperationException("can not resolve operator: " + operator);
		}
	}
}
